Filter
过滤客户端和服务器之间的请求。是 web 三大核心(Servlet【处理请求】,Filter【过滤请求,响应】,Listener【监听器】)组件之一。
三大核心组件的共同点:
- 实现某个接口
- 注册
简单示例
新建一个类,并且实现 javax.servlet.Filter 接口,那么这个类就是 Filter 的实现类,需要在 web.xml 进行注册,注册和 Servlet 类似。如下所示:
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <filter> <filter-name>TestFilter</filter-name> <filter-class>com.itguigu.filter.TestFilter</filter-class> </filter> <filter-mapping> <filter-name>TestFilter</filter-name> <url-pattern>/UserServlet</url-pattern> </filter-mapping> <servlet> <description></description> <display-name>UserServlet</display-name> <servlet-name>UserServlet</servlet-name> <servlet-class>com.itguigu.servlet.UserServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UserServlet</servlet-name> <url-pattern>/UserServlet</url-pattern> </servlet-mapping> </web-app>
|
TestFilter.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package com.itguigu.filter;
import java.io.IOException;
import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse;
public class TestFilter implements Filter{ @Override public void destroy() { System.out.println("销毁"); }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("doFilter"); chain.doFilter(request, response); }
@Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("初始化"); } }
|
UserServlet.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.itguigu.servlet;
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
public class UserServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("处理用户请求"); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
|
生命周期
Filter 生命周期
顺序 |
执行时间 |
执行次数 |
构造器 |
启动服务器时 |
执行一次 |
init |
启动服务器时 |
执行一次 |
doFilter |
过滤请求时 |
执行多次 |
destroy |
关闭服务器时 |
执行一次 |
Servlet 生命周期
顺序 |
执行时间 |
执行次数 |
构造器 |
第一次接受到请求时 |
执行一次 |
init |
第一次接受到请求时 |
执行一次 |
service |
每次接受到请求时都会执行 |
执行多次 |
destroy |
关闭服务器时 |
执行一次 |
工作原理
- 请求发送
- 执行过滤器中 doFilter 放行前代码
- 放行
- 执行 Servlet 代码,做出响应
- 执行过滤器中 doFilter 放行后代码
- 做出响应
多个 Filter 执行流程
遵循先进后出原则,即:请求 —> Filter1 放行前 —> Filter2 放行前 —> Filter3 放行前 —> 处理请求, 做出响应 —> Filter3 放行后 —> Filter2 放行后 —> Filter1 放行后 —> 响应
即执行顺序取决于 web.xml 中的 filter-mapping 的顺序。和 filter 无关,例如,下面示例中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <filter> <filter-name>TestFilter</filter-name> <filter-class>com.itguigu.filter.TestFilter</filter-class> </filter> <servlet> <description></description> <display-name>UserServlet</display-name> <servlet-name>UserServlet</servlet-name> <servlet-class>com.itguigu.servlet.UserServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UserServlet</servlet-name> <url-pattern>/UserServlet</url-pattern> </servlet-mapping> <filter> <display-name>UserServletFilter</display-name> <filter-name>UserServletFilter</filter-name> <filter-class>com.itguigu.filter.UserServletFilter</filter-class> </filter> <filter-mapping> <filter-name>UserServletFilter</filter-name> <url-pattern>/UserServlet</url-pattern> </filter-mapping> <filter-mapping> <filter-name>TestFilter</filter-name> <url-pattern>/UserServlet</url-pattern> </filter-mapping> </web-app>
|
URL 配置规则
精准匹配
方式1
1 2 3 4 5 6 7 8
| <filter> <filter-name>TestFilter</filter-name> <filter-class>com.itguigu.filter.TestFilter</filter-class> </filter> <filter-mapping> <filter-name>TestFilter</filter-name> <url-pattern>/UserServlet</url-pattern> </filter-mapping>
|
方式2
1 2 3 4 5 6 7 8 9
| <filter> <filter-name>TestFilter</filter-name> <filter-class>com.itguigu.filter.TestFilter</filter-class> </filter> <filter-mapping> <filter-name>TestFilter</filter-name> <servlet-name>UserServlet</servlet-name> </filter-mapping>
|
模糊匹配
前置模糊(*在最前面)
1 2 3 4 5 6 7 8
| <filter> <filter-name>TestFilter</filter-name> <filter-class>com.itguigu.filter.TestFilter</filter-class> </filter> <filter-mapping> <filter-name>TestFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping>
|
后置模糊(*在最后面)
1 2 3 4 5 6 7 8
| <filter> <filter-name>TestFilter</filter-name> <filter-class>com.itguigu.filter.TestFilter</filter-class> </filter> <filter-mapping> <filter-name>TestFilter</filter-name> <url-pattern>/pages/user/*</url-pattern> </filter-mapping>
|
封装 HttpFilter
将 Filter 进行封装,封装为 HttpFilter。并重载 doFilter 方法,将 request 类型改为 HttpServletRequest。response 类型改为 HttpServletResponse。并将 doFilter 方法抽象化,让子类继承实现,并提供获取 FilterConfig 的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| package com.itguigu.filter;
import java.io.IOException;
import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
public abstract class HttpFilter implements Filter { private FilterConfig filterConfig; public HttpFilter() {} public void destroy() {} public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; doFilter(req, res, chain); }
public abstract void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException ; public void init(FilterConfig fConfig) throws ServletException { this.filterConfig = fConfig; }
public FilterConfig getFilterConfig() { return filterConfig; } }
|
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.itguigu.filter;
import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
public class HttpFilterTest extends HttpFilter {
@Override public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { FilterConfig filterConfig2 = this.getFilterConfig(); System.out.println(filterConfig2); chain.doFilter(request, response); } }
|
优化字符集
新建一个 CharSetFilter,并继承 HttpFilter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package com.itguigu.filter;
import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
public class CharSetFilter extends HttpFilter{ @Override public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws IOException, ServletException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=UTF-8"); chain.doFilter(request, response); } }
|
将 CharSetFilter 过滤器应用到 / 下所有的请求中
1 2 3 4 5 6 7 8 9
| <filter> <display-name>CharSetFilter</display-name> <filter-name>CharSetFilter</filter-name> <filter-class>com.itguigu.filter.CharSetFilter</filter-class> </filter> <filter-mapping> <filter-name>CharSetFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
|
上面的编码格式在 CharSetFilter 是固定写死的。我们还可以在 xml 利用 init-param 进行设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <filter> <display-name>CharSetFilter</display-name> <filter-name>CharSetFilter</filter-name> <filter-class>com.itguigu.filter.CharSetFilter</filter-class> <init-param> <param-name>code</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharSetFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.itguigu.filter;
import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
public class CharSetFilter extends HttpFilter{ @Override public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws IOException, ServletException { FilterConfig filterConfig = this.getFilterConfig(); String code = filterConfig.getInitParameter("code"); request.setCharacterEncoding(code); response.setContentType("text/html;charset=UTF-8"); chain.doFilter(request, response); } }
|